﻿using System;
using System.Linq;
using System.Collections.Generic;
using Microsoft.VisualStudio.XmlEditor;
using System.Xml.Linq;

namespace CodeCounsel.SharePoint.RibbonDesigner.Model
{
    public class CommandUIModel
    {
        XmlStore _store;
        XmlModel _elementsDefinitionDataModel;
        XDocument _document;
        public CommandUIDocument CommandUIDefinition { get; private set; }
        public ElementsDocument ElementsDefinition { get; private set; }

        public CommandUIModel(XmlStore store)
	    {
            _store = store;
	    }

        public void LoadDefinition(Uri uri)
        {
            XmlModel dataModel = _store.OpenXmlModel(uri);
            XDocument document = dataModel.Document;
            Schema.Validate(document);
            CommandUIDefinition = DomainModelFactory.CreateDefinition(this, document);
        }

        internal IDisposable BeginEdit(string action)
        {
            object state = null;
            return _store.BeginEditingScope(action, state);
        }
        
        internal void EndEdit(IDisposable context)
        {
            XmlEditingScope scope = context as XmlEditingScope;
            if (scope == null)
            {
                throw new ArgumentException("context not recognized");
            }
            scope.Complete();
        }

        public void AddElementsDefinition(Uri uri)
        {
            _elementsDefinitionDataModel = _store.OpenXmlModel(uri);
            _elementsDefinitionDataModel.BufferReloaded += new EventHandler(DataModel_BufferReloaded);
            Reload();
        }

        public IEnumerable<CommandUIDefinition> GetExtensions(DomainElement element)
        {
            //TODO: Check if this is smart enough, pretty long query
            return ElementsDefinition.Elements != null ?
                ElementsDefinition.Elements.CustomActions
                    .Where(ca => ca.IsCommandUIAction)
                    .Select(ca => ca.CommandUIExtension)
                    .Select(cue => cue.CommandUIDefinitions)
                    .SelectMany(cued => cued)
                    .Where(cued => element.IsExtensionForElement(cued))
                : new CommandUIDefinition[] { };
        }

        protected virtual void OnElementsDefinitionChanged(EventArgs e)
        {
            if (ElementsDefinitionChanged != null)
            {
                ElementsDefinitionChanged(this, e);
            }
        }

        void Document_Changed(object sender, XObjectChangeEventArgs e)
        {
            if (sender is XElement)
            {
                ReloadElementsDefinition();
            }
        }

        void DataModel_BufferReloaded(object sender, EventArgs e)
        {
            Reload();
        }

        void ReloadElementsDefinition()
        {
            ElementsDefinition = DomainModelFactory.CreateElementsDefinition(this, _elementsDefinitionDataModel.Document);
            OnElementsDefinitionChanged(EventArgs.Empty);
        }

        void Reload()
        {
            if (_document != null)
            {
                _document.Changed -= Document_Changed;
            }
            _document = _elementsDefinitionDataModel.Document;
            Schema.Validate(_document);
            _document.Changed += Document_Changed;
            ElementsDefinition = DomainModelFactory.CreateElementsDefinition(this, _document);
            OnElementsDefinitionChanged(EventArgs.Empty);
        }

        public event EventHandler ElementsDefinitionChanged;
    }
}
